  /***************************************************************************
  *   Copyright (C) 2007 by Alexandre Masselot,,,   *
  *   alex@alex-laptop   *
  *                                                                         *
  *   This program is free software; you can redistribute it and/or modify  *
  *   it under the terms of the GNU Library General Public License as       *
  *   published by the Free Software Foundation; either version 2 of the    *
  *   License, or (at your option) any later version.                       *
  *                                                                         *
  *   This program is distributed in the hope that it will be useful,       *
  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
  *   GNU General Public License for more details.                          *
  *                                                                         *
  *   You should have received a copy of the GNU Library General Public     *
  *   License along with this program; if not, write to the                 *
  *   Free Software Foundation, Inc.,                                       *
  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
  ***************************************************************************/
  #include "peptidemodifier.h"
//#include "peptidepmf.h"

  namespace bol{
  PeptideModifier::PeptideModifier()
  {
    AminoAcid::initChar2mass();
    m_cptChar=32;
      for(int i=0; i<29; i++){
        m_charMapper[i]=new unsigned char[2];
        m_charMapper[i][0]=static_cast<unsigned char>(i);
        m_charMapper[i][1]=0;
      }
      for (int i=0; i<256; i++){
        m_origChar[i]=0;
        m_origModif[i]=0;
      }
      for (unsigned char i=0; i<29; i++){
        m_origChar[i]=AminoAcid::reduced2aa(i);
      }
  }


  void PeptideModifier::addModif(Modification* mod, const bool isVariable){
    //todo check for a variable after a fix setting or vice versa or doubly fix modif
    for (const char *modifAA=mod->aminoAcids().c_str(); *modifAA; modifAA++){
      assert(static_cast<int>(m_cptChar)!=255);
      m_cptChar++;
      //todo see if all (int) cann be replaced by (byte)
      //keep track of the orignal amino acid
      m_origChar[static_cast<int>(m_cptChar)]=*modifAA;
      //keep track of the original modif
      m_origModif[static_cast<int>(m_cptChar)]=mod;
      
      unsigned char i=AminoAcid::aa2reduced(*modifAA);
      //set the mass as a shifted modif
      AminoAcid::setChar2mass(m_cptChar, AminoAcid::char2mass(i)+mod->deltaMass());

      if(isVariable){
        unsigned char* tmp=m_charMapper[i];
        int l=0;
        for (unsigned char *c=m_charMapper[i]; *c; c++){
          l++;
        }
        l++;
        m_charMapper[i]=new unsigned char[l+1];
        memcpy(m_charMapper[i], tmp, l-1);
        m_charMapper[i][l-1]=m_cptChar;
        m_charMapper[i][l]=0;
        //todo check this delete
        //delete[] tmp;
      }else{
        //check length is 0 
        //assert(strlen(static_cast<char*>(charMapper[i]))==1);
        m_charMapper[i][0]=m_cptChar;
        m_charMapper[i][1]=0;
      }
      string k=string("")+ *modifAA+"-"+mod->name();
      m_modifaadico[k]=m_cptChar;
    }
  }

  void PeptideModifier::printPeptide(ostream& out, const Peptide *pept){
    if(!pept->sequence()){
      out<<"NULL";
      return;
    }
    for (unsigned char *c=pept->sequence(); *c; c++){
        out<<m_origChar[static_cast<int>(*c)];
        if(m_origModif[static_cast<int>(*c)]){
            out<<"{"<< m_origModif[static_cast<int>(*c)]->name()<<"}";
        }
    }
    //todo catch PeptidePMF casting and the prints also the list of modif
    
  /*  if(PeptidePMF *pmfpept=dynamic_cast<PeptidePMF*>(pept)){
      for(int i=0; i<pmfpept->vModif().size(); i++){
        out<<" "<<pmfpept->vNbModif()[i]<<"x"<<pmfpept->vModif()[i]->name();
      }
    }*/
  }

  /**
   * 
   * @param sequence 
   * @param modifs 
   * @return 
   */
  Peptide* PeptideModifier::peptide(const string sequence, const string modifs){
    typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
    boost::char_separator<char> sep(":", "", boost::keep_empty_tokens);
    tokenizer tokens(modifs, sep);
    tokenizer::iterator tok_iter = tokens.begin();
    Peptide* p=new Peptide(sequence);
    for(int i=0; i<p->length(); i++){
      if(tok_iter==tokens.end()){
        cerr<<"invalid number of modif "<<sequence<<"/"<<modifs<<endl;
        exit(1);
      }
      string modstr(*tok_iter);
      if(modstr.length()>0){
        unsigned char c=p->sequence()[i];
        string k=string("")+((char )AminoAcid::reduced2aa(c))+"-"+modstr;
        if(m_modifaadico.find(k)==m_modifaadico.end()){
          cerr<<"invalid modifaa key ["<<k<<"]"<<endl;
          exit(1);
        }
        p->sequence()[i]=m_modifaadico[k];
      }
      ++tok_iter;
    }
    return p;
  }

  ostream& operator<<(ostream& out, const PeptideModifier& pm){
    for(int i=1; i<29; i++){
      out<<i<<"\t";
      for(unsigned char* c=pm.m_charMapper[i]; *c; c++){
        out<<pm.m_origChar[static_cast<int>(*c)]<<"("<<AminoAcid::char2mass(*c)<<")";
        if(pm.m_origModif[static_cast<int>(*c)]){
            out<<"+"<< pm.m_origModif[static_cast<int>(*c)]->name();
        }
        out<<" ";
      }
      out<<"\n";
    }
    return out;
  }
}
